/**
 * 
 */
package server.internal;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import server.StorageDevice;
import server.StorageUnit;
import server.StorageUnitID;

import commons.Preconditions;
import commons.exception.StorageUnitNotFoundException;
import commons.internal.StorageUnitIDGenerator;
import commons.operation.Operation;
import commons.operation.OperationParameter;

/**
 * @author armstrong
 * 
 */
public class DefaultStorageDevice implements StorageDevice {

	private final Map<StorageUnitID, StorageUnit>	storageUnits;
	private final StorageUnitIDGenerator			idGenerator;
	private final String							storageDeviceDirectoryPath;

	public DefaultStorageDevice(final String storageDeviceDirectoryPath) {

		Preconditions.checkNotNull(
				"storageDeviceDirectoryPath must not be null.",
				storageDeviceDirectoryPath);

		storageUnits = new HashMap<StorageUnitID, StorageUnit>();
		idGenerator = new StorageUnitIDGenerator();
		this.storageDeviceDirectoryPath = storageDeviceDirectoryPath;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageDevice#createStorageUnit()
	 */
	@Override
	public StorageUnitID createStorageUnit() throws IOException {

		final StorageUnitID storageUnitId = idGenerator.generateID();
		final StorageUnit storageUnit = DefaultStorageUnit.createStorageUnit(
				storageDeviceDirectoryPath, storageUnitId);
		storageUnits.put(storageUnitId, storageUnit);

		return storageUnitId;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageDevice#list()
	 */
	@Override
	public Set<StorageUnitID> list() {

		return storageUnits.keySet();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageDevice#operateOverStorageUnit(commons.Operation,
	 * server.StorageUnitId)
	 */
	@Override
	public Object operateOverStorageUnit(final Operation operation,
			final StorageUnitID storageUnitId)
			throws StorageUnitNotFoundException, IOException {

		final StorageUnit storageUnit = storageUnits.get(storageUnitId);
		Object result = null;

		if (storageUnit == null) {
			throw new StorageUnitNotFoundException("storageUnit "
					+ storageUnitId + " does not exist.");
		}

		switch (operation.type()) {
			case Write: {
				result = storageUnit.write((ByteBuffer) operation
						.getParameter(OperationParameter.ByteBuffer));
			}
				break;

			case Read: {
				result = storageUnit.read((ByteBuffer) operation
						.getParameter(OperationParameter.ByteBuffer));
			}
				break;

			case Seek: {
				storageUnit.seek((Long) operation
						.getParameter(OperationParameter.Position));
			}
				break;

			case SetSize: {
				storageUnit.setSize((Long) operation
						.getParameter(OperationParameter.Size));
			}
				break;

			case Size: {
				result = storageUnit.size();
			}
				break;
		}

		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see server.StorageDevice#removeStorageUnit(server.StorageUnitId)
	 */
	@Override
	public void removeStorageUnit(final StorageUnitID storageUnitId)
			throws StorageUnitNotFoundException, IOException {

		final StorageUnit removed = storageUnits.remove(storageUnitId);

		if (removed == null) {
			throw new StorageUnitNotFoundException();
		}

		removed.delete();
	}

}
